package com.android.common.util;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class StringUtil {
	public static final String EMPTY = "";
	public static final String NULL = "null";
	public static final int INDEX_NOT_FOUND = -1;
	public static final String ZERO = "0";
	public static final String DEFAULT_SYMBOL = "...";

	public static final Pattern NUMBER_PATTERN = Pattern.compile("[0-9]*");

	public static final Pattern CHINESE_PATTERN = Pattern
			.compile("[\u4e00-\u9fa5]");

	public static final NumberFormat PRICE_FORMATTER = NumberFormat
			.getInstance();
	public static final Pattern MONEY_PATTERN = Pattern
			.compile("[0-9]*.?[0-9]{1,2}");

	public static final String SYMBOL = "¥";

	static {
		PRICE_FORMATTER.setMaximumFractionDigits(2);
		PRICE_FORMATTER.setMinimumFractionDigits(2);
		// PRICE_FORMATTER.setGroupingUsed(false);
	}

	/**
	 * 判断字符串是否为空
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isEmpty(String str) {
		if (str == null || EMPTY.equals(str)) {
			return true;
		}
		return false;
	}

	public static boolean isEmptyOrNullStr(String str) {
		return isEmpty(str) || NULL.equalsIgnoreCase(str);
	}

	public static boolean isBlank(CharSequence cs) {
		int strLen;
		if (cs == null || (strLen = cs.length()) == 0) {
			return true;
		}
		for (int i = 0; i < strLen; i++) {
			if (Character.isWhitespace(cs.charAt(i)) == false) {
				return false;
			}
		}
		return true;
	}

	public static boolean isNotBlank(CharSequence cs) {
		return !isBlank(cs);
	}

	public static boolean isEqualsZero(String str) {
		if (isBlank(str)) {
			return false;
		}
		return ZERO.equals(str.trim());
	}

	public static boolean isNotEqualsZero(String str) {
		return !isEqualsZero(str);
	}

	/**
	 * <p>
	 * Gets the substring before the first occurrence of a separator. The
	 * separator is not returned.
	 * </p>
	 * 
	 * <p>
	 * A {@code null} string input will return {@code null}. An empty ("")
	 * string input will return the empty string. A {@code null} separator will
	 * return the input string.
	 * </p>
	 * 
	 * <p>
	 * If nothing is found, the string input is returned.
	 * </p>
	 * 
	 * <pre>
	 * StringUtils.substringBefore(null, *)      = null
	 * StringUtils.substringBefore("", *)        = ""
	 * StringUtils.substringBefore("abc", "a")   = ""
	 * StringUtils.substringBefore("abcba", "b") = "a"
	 * StringUtils.substringBefore("abc", "c")   = "ab"
	 * StringUtils.substringBefore("abc", "d")   = "abc"
	 * StringUtils.substringBefore("abc", "")    = ""
	 * StringUtils.substringBefore("abc", null)  = "abc"
	 * </pre>
	 * 
	 * @param str
	 *            the String to get a substring from, may be null
	 * @param separator
	 *            the String to search for, may be null
	 * @return the substring before the first occurrence of the separator,
	 *         {@code null} if null String input
	 * @since 2.0
	 */
	public static String substringBefore(String str, String separator) {
		if (isEmpty(str) || separator == null) {
			return str;
		}
		if (separator.length() == 0) {
			return EMPTY;
		}
		int pos = str.indexOf(separator);
		if (pos == INDEX_NOT_FOUND) {
			return str;
		}
		return str.substring(0, pos);
	}

	/**
	 * <p>
	 * Gets the String that is nested in between two Strings. Only the first
	 * match is returned.
	 * </p>
	 * 
	 * <p>
	 * A {@code null} input String returns {@code null}. A {@code null}
	 * open/close returns {@code null} (no match). An empty ("") open and close
	 * returns an empty string.
	 * </p>
	 * 
	 * <pre>
	 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
	 * StringUtils.substringBetween(null, *, *)          = null
	 * StringUtils.substringBetween(*, null, *)          = null
	 * StringUtils.substringBetween(*, *, null)          = null
	 * StringUtils.substringBetween("", "", "")          = ""
	 * StringUtils.substringBetween("", "", "]")         = null
	 * StringUtils.substringBetween("", "[", "]")        = null
	 * StringUtils.substringBetween("yabcz", "", "")     = ""
	 * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
	 * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
	 * </pre>
	 * 
	 * @param str
	 *            the String containing the substring, may be null
	 * @param open
	 *            the String before the substring, may be null
	 * @param close
	 *            the String after the substring, may be null
	 * @return the substring, {@code null} if no match
	 * @since 2.0
	 */
	public static String substringBetween(String str, String open, String close) {
		if (str == null || open == null || close == null) {
			return null;
		}
		int start = str.indexOf(open);
		if (start != INDEX_NOT_FOUND) {
			int end = str.indexOf(close, start + open.length());
			if (end != INDEX_NOT_FOUND) {
				return str.substring(start + open.length(), end);
			}
		}
		return null;
	}

	/**
	 * <p>
	 * Gets the substring after the first occurrence of a separator. The
	 * separator is not returned.
	 * </p>
	 * 
	 * <p>
	 * A {@code null} string input will return {@code null}. An empty ("")
	 * string input will return the empty string. A {@code null} separator will
	 * return the empty string if the input string is not {@code null}.
	 * </p>
	 * 
	 * <p>
	 * If nothing is found, the empty string is returned.
	 * </p>
	 * 
	 * <pre>
	 * StringUtils.substringAfter(null, *)      = null
	 * StringUtils.substringAfter("", *)        = ""
	 * StringUtils.substringAfter(*, null)      = ""
	 * StringUtils.substringAfter("abc", "a")   = "bc"
	 * StringUtils.substringAfter("abcba", "b") = "cba"
	 * StringUtils.substringAfter("abc", "c")   = ""
	 * StringUtils.substringAfter("abc", "d")   = ""
	 * StringUtils.substringAfter("abc", "")    = "abc"
	 * </pre>
	 * 
	 * @param str
	 *            the String to get a substring from, may be null
	 * @param separator
	 *            the String to search for, may be null
	 * @return the substring after the first occurrence of the separator,
	 *         {@code null} if null String input
	 * @since 2.0
	 */
	public static String substringAfter(String str, String separator) {
		if (isEmpty(str)) {
			return str;
		}
		if (separator == null) {
			return EMPTY;
		}
		int pos = str.indexOf(separator);
		if (pos == INDEX_NOT_FOUND) {
			return EMPTY;
		}
		return str.substring(pos + separator.length());
	}

	public static CharSequence defaultEmptyIfNull(CharSequence c) {
		return c == null ? EMPTY : c;
	}

	public static String defaultIfBlank(String str) {
		return defaultIfBlank(str, EMPTY);
	}

	public static String defaultIfBlank(String str, String defaultStr) {
		return isBlank(str) ? defaultStr : str;
	}

	public static int getLength(CharSequence c) {
		return c == null ? 0 : c.length();
	}

	/**
	 * <p>
	 * Splits the provided text into an array, separators specified. This is an
	 * alternative to using StringTokenizer.
	 * </p>
	 * 
	 * <p>
	 * The separator is not included in the returned String array. Adjacent
	 * separators are treated as one separator. For more control over the split
	 * use the StrTokenizer class.
	 * </p>
	 * 
	 * <p>
	 * A {@code null} input String returns {@code null}. A {@code null}
	 * separatorChars splits on whitespace.
	 * </p>
	 * 
	 * <pre>
	 * StringUtils.split(null, *)         = null
	 * StringUtils.split("", *)           = []
	 * StringUtils.split("abc def", null) = ["abc", "def"]
	 * StringUtils.split("abc def", " ")  = ["abc", "def"]
	 * StringUtils.split("abc  def", " ") = ["abc", "def"]
	 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
	 * </pre>
	 * 
	 * @param str
	 *            the String to parse, may be null
	 * @param separatorChars
	 *            the characters used as the delimiters, {@code null} splits on
	 *            whitespace
	 * @return an array of parsed Strings, {@code null} if null String input
	 */
	public static String[] split(String str, String separatorChars) {
		return splitWorker(str, separatorChars, -1, false);
	}

	/**
	 * Performs the logic for the {@code split} and
	 * {@code splitPreserveAllTokens} methods that return a maximum array
	 * length.
	 * 
	 * @param str
	 *            the String to parse, may be {@code null}
	 * @param separatorChars
	 *            the separate character
	 * @param max
	 *            the maximum number of elements to include in the array. A zero
	 *            or negative value implies no limit.
	 * @param preserveAllTokens
	 *            if {@code true}, adjacent separators are treated as empty
	 *            token separators; if {@code false}, adjacent separators are
	 *            treated as one separator.
	 * @return an array of parsed Strings, {@code null} if null String input
	 */
	private static String[] splitWorker(String str, String separatorChars,
			int max, boolean preserveAllTokens) {
		// Performance tuned for 2.0 (JDK1.4)
		// Direct code is quicker than StringTokenizer.
		// Also, StringTokenizer uses isSpace() not isWhitespace()

		if (str == null) {
			return null;
		}
		int len = str.length();
		if (len == 0) {
			return ArrayUtil.EMPTY_STRING_ARRAY;
		}
		List<String> list = new ArrayList<String>();
		int sizePlus1 = 1;
		int i = 0, start = 0;
		boolean match = false;
		boolean lastMatch = false;
		if (separatorChars == null) {
			// Null separator means use whitespace
			while (i < len) {
				if (Character.isWhitespace(str.charAt(i))) {
					if (match || preserveAllTokens) {
						lastMatch = true;
						if (sizePlus1++ == max) {
							i = len;
							lastMatch = false;
						}
						list.add(str.substring(start, i));
						match = false;
					}
					start = ++i;
					continue;
				}
				lastMatch = false;
				match = true;
				i++;
			}
		} else if (separatorChars.length() == 1) {
			// Optimise 1 character case
			char sep = separatorChars.charAt(0);
			while (i < len) {
				if (str.charAt(i) == sep) {
					if (match || preserveAllTokens) {
						lastMatch = true;
						if (sizePlus1++ == max) {
							i = len;
							lastMatch = false;
						}
						list.add(str.substring(start, i));
						match = false;
					}
					start = ++i;
					continue;
				}
				lastMatch = false;
				match = true;
				i++;
			}
		} else {
			// standard case
			while (i < len) {
				if (separatorChars.indexOf(str.charAt(i)) >= 0) {
					if (match || preserveAllTokens) {
						lastMatch = true;
						if (sizePlus1++ == max) {
							i = len;
							lastMatch = false;
						}
						list.add(str.substring(start, i));
						match = false;
					}
					start = ++i;
					continue;
				}
				lastMatch = false;
				match = true;
				i++;
			}
		}
		if (match || preserveAllTokens && lastMatch) {
			list.add(str.substring(start, i));
		}
		return list.toArray(new String[list.size()]);
	}

	public static boolean isNumeric(String str) {
		if (isBlank(str)) {
			return false;
		}
		return NUMBER_PATTERN.matcher(str).matches();
	}

	public static String formatPrice(String price) {
		return SYMBOL + defaultIfBlank(price, ZERO);
	}

	public static String formatPrice(double price) {
		return SYMBOL + PRICE_FORMATTER.format(price);
	}

	public static String formatPrice(float price) {
		return SYMBOL + PRICE_FORMATTER.format(price);
	}

	public static String trim(String str) {
		return str == null ? null : str.trim();
	}

	public static String format(String str, Object... params) {
		if (isBlank(str)) {
			return EMPTY;
		}
		return MessageFormat.format(str, params);
	}

	public static boolean equals(CharSequence cs1, CharSequence cs2) {
		return cs1 == null ? cs2 == null : cs1.equals(cs2);
	}

	/**
	 * 获得字符串的真实长度
	 * 
	 * <pre>
	 * StringUtils.getLength(null)      = 0
	 * StringUtils.getLength("")        = 0
	 * StringUtils.getLength(" ")       = 0
	 * StringUtils.getLength("bob")     = 3
	 * StringUtils.getLength("  bob  ") = 7
	 * StringUtils.getLength("测试")     = 4
	 * </pre>
	 * 
	 * @param str
	 * @return
	 */
	public static int getRealLength(String str) {
		if (isBlank(str)) {
			return 0;
		}
		return str.getBytes().length;
	}

	/**
	 * 按字符截取字符串,可区分中文，英文
	 * 
	 * 
	 * @param str
	 * @param begin
	 *            字符串起始位置
	 * @param end
	 *            字符串结束位置
	 * @param symbol
	 *            结束符
	 * @return
	 */
	public static String subString(String str, int begin, int end, String symbol) {
		if (isBlank(str)) {
			return EMPTY;
		}

		StringBuffer result = new StringBuffer(0);
		byte[] bytes = str.getBytes();
		int length = bytes.length;

		if (begin == 0 && end > length) {
			return str;
		}

		if (end > length)
			end = length;
		if (end < 0)
			end += length;

		if (begin < 0)
			begin = 0;

		if (begin > end)
			return result.toString();

		int count = 0;

		if (begin > 0) {
			begin = subString(str, 0, begin, EMPTY).getBytes().length;
		}
		for (int i = 0; i < end - begin; i++) {
			if (bytes[i] < 0)
				count++;
		}
		if (count % 2 != 0)
			--end;

		result.append(new String(bytes, begin, end - begin)).append(symbol);

		return result.toString();
	}

	/**
	 * 按字符截取字符串,可区分中文，英文，默认结束符为...
	 * 
	 * @param str
	 * @param begin
	 * @param end
	 * @return
	 */
	public static String subString(String str, int begin, int end) {
		return subString(str, begin, end, DEFAULT_SYMBOL);
	}

	/**
	 * 按字符截取字符串
	 * 
	 * @param str
	 * @param end
	 * @param symbol
	 * @return
	 */
	public static String subString(String str, int end, String symbol) {
		return subString(str, 0, end, symbol);
	}

	/**
	 * 按字符截取字符串
	 * 
	 * @param str
	 * @param end
	 * @return
	 */
	public static String subString(String str, int end) {
		return subString(str, 0, end);
	}

	public static String replaceLineBreakAndTrim(String str) {
		if (isBlank(str)) {
			return EMPTY;
		}
		return str.replaceAll("\n", EMPTY).trim();
	}

	public static boolean contains(String str, String searchStr) {
		if (str == null || searchStr == null) {
			return false;
		}
		return str.indexOf(searchStr) >= 0;
	}

	public static String defaultEmptyIfNullOrNullstr(String s) {
		return s == null || isEmptyOrNullStr(s) ? EMPTY : s;
	}

	public static String objectToString(Object o) {
		return o == null ? EMPTY : o.toString();
	}

	public static String encode(String str) {
		try {
			return URLEncoder.encode(str, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			return str;
		}
	}

	public static boolean isMoney(String str) {
		if (isBlank(str)) {
			return false;
		}
		return MONEY_PATTERN.matcher(str).matches();
	}

	public static String replace(String text, String searchString,
			String replacement) {
		return replace(text, searchString, replacement, -1);
	}

	public static String replaceOnce(String text, String searchString,
			String replacement) {
		return replace(text, searchString, replacement, 1);
	}

	public static String replace(String text, String searchString,
			String replacement, int max) {
		if (isEmpty(text) || isEmpty(searchString) || replacement == null
				|| max == 0) {
			return text;
		}
		int start = 0;
		int end = text.indexOf(searchString, start);
		if (end == INDEX_NOT_FOUND) {
			return text;
		}
		int replLength = searchString.length();
		int increase = replacement.length() - replLength;
		increase = (increase < 0 ? 0 : increase);
		increase *= (max < 0 ? 16 : (max > 64 ? 64 : max));
		StringBuilder buf = new StringBuilder(text.length() + increase);
		while (end != INDEX_NOT_FOUND) {
			buf.append(text.substring(start, end)).append(replacement);
			start = end + replLength;
			if (--max == 0) {
				break;
			}
			end = text.indexOf(searchString, start);
		}
		buf.append(text.substring(start));
		return buf.toString();
	}
}
